package com.gopay.common.util.security;

import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * SQL注入和XSS攻击的防御过滤器类
 * 
 * @SQLInjectAndXSSDefenseFilter.java
 * @author fanghw
 * @2016年11月3日 上午10:04:08 www.gopay.com.cn Inc.All rights reserved.
 */
public class SQLInjectAndXSSDefenseFilter implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(SQLInjectAndXSSDefenseFilter.class);

    // 需要过滤的URI后缀 【注意：图片，样式文件不需要过滤】
    private static String[] uriSuffixArr = new String[] { ".shtml", ".html", ".htm", ".js", ".do" };

    // 恶意字符转码表
    private static final Map<Character, String> evilCharsMap = new HashMap<Character, String>();
    // 恶意字符数组
    private static Character[] ecArr = null;

    static {
        // 恶意字符转码表初始化   
        //*********************************************
        // 【注意】因为base64编码后里有+，/，=号这三个字符，所以不能过滤
        //*********************************************
        evilCharsMap.put('<', "&lt;");// 小于号
        evilCharsMap.put('>', "&gt;");// 大于号
        evilCharsMap.put('\'', "&apos;");// 单引号
        evilCharsMap.put('"', "&quot;");// 双引号
        evilCharsMap.put('$', "&#36;");// 美元标识
        evilCharsMap.put('%', "&#37;");// 百分号
        evilCharsMap.put('\\', "&#92;");// 反斜杠     
        evilCharsMap.put('(', "（");// 左小括号
        evilCharsMap.put(')', "）");// 右小括号

        // 恶意字符数组初始化
        ecArr = new Character[evilCharsMap.keySet().size()];

        Iterator<Character> ecIter = evilCharsMap.keySet().iterator();
        int i = 0;
        while (ecIter.hasNext()) {
            ecArr[i++] = ecIter.next();
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        String uri = req.getRequestURI().toLowerCase();

        // 只过滤配置的URI后缀
        boolean match = false;
        for (int i = 0; i < uriSuffixArr.length; i++) {
            if (uri.endsWith(uriSuffixArr[i])) {
                match = true;
                break;
            }
        }

        if (match) {
            Map pm=new HashMap(request.getParameterMap()); 
            boolean isWrite=false;
            // 遍历request中的参数，若存在不安全脚本，则转码处理
            for (Enumeration enumeration = request.getParameterNames(); enumeration.hasMoreElements();) {
                String eleName = (String) enumeration.nextElement();                
                String[] eleValues=request.getParameterValues(eleName);
                
                boolean exists = false;
                if(eleValues!=null){
                    for(int i=0;i<eleValues.length;i++){
                        String eleValue=eleValues[i];
                        for (int j = 0; j < ecArr.length; j++) {
                            Character ec = ecArr[j];
                            if (eleValue != null && eleValue.contains(ec.toString())) {
                                eleValue = eleValue.replace(ec.toString(), evilCharsMap.get(ec));
                                exists = true;
                            }
                        }
                        eleValues[i]=eleValue;
                    }
                }               
                

                // 替换参数内容
                if (exists) {
                    pm.put(eleName, eleValues);  //String[]  防止Spring解析时  类型转换异常
                    isWrite=true;
                    
                    logger.info(String.format("恶意字符过滤,URI=%s,参数名=%s,参数值=%s,过滤后的参数值=%s", uri,eleName,Arrays.toString(request.getParameterValues(eleName)),Arrays.toString(eleValues)));
                }
            }
            
            if(isWrite){
                WritableParamsRequestWrapper wrapper=new WritableParamsRequestWrapper(req,pm);
                request=wrapper;
            }
            
        }

        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    
    @Override
    public void destroy() {

    }
    
    

}
